package com.kevin.servlet;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javax.activation.MimetypesFileTypeMap;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.kevin.annotation.ResponseBody;
import com.kevin.configuration.Configuration;
import com.kevin.utils.string.KnStringUtils;

public class DispatcherServlet extends HttpServlet {

	public DispatcherServlet() {
		super();
	}

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	private static final MimetypesFileTypeMap MIMETYPE_MAP = new MimetypesFileTypeMap();
	private static final Logger LOGGER = LoggerFactory.getLogger(DispatcherServlet.class);

	@Override
	public void service(HttpServletRequest request, HttpServletResponse response) {
		String appName = request.getSession().getServletContext().getContextPath();
		String path = request.getRequestURI().substring(appName.length());

		LOGGER.info("Request path is {}", path);

		// /controller/action/ => controller/action
		path = StringUtils.removeStart(StringUtils.removeEnd(path, "/"), "/");
		LOGGER.info("Request path is {}", path);
		// 默认controller、默认 action
		if (StringUtils.isEmpty(path)) {
			if (StringUtils.isEmpty(Configuration.controller.getDefaultController())) {
				path = "home";
			} else {
				path = Configuration.controller.getDefaultController();
			}
		}

		// 上面的判断会造成 controller => controller/action
		if (!path.contains("/")) {
			if (StringUtils.isEmpty(Configuration.controller.getDefaultAction())) {
				path += "/index";
			} else {
				path += "/" + Configuration.controller.getDefaultAction();
			}
		}

		String[] paths = path.split("/", 2);

		String controllerClazeName = Configuration.controller.getPackageName() + "."
				+ KnStringUtils.upperFirst(paths[0]) + "Controller";
		String methodName = paths[1];

		try {
			Class<?> controllerClazz = Class.forName(controllerClazeName);
			Method method = controllerClazz.getMethod(methodName,
					new Class<?>[] { HttpServletRequest.class, HttpServletResponse.class });

			Object controller = controllerClazz.newInstance();
			if (isAnnotated(method, ResponseBody.class)) {
                Object result = method.invoke(controller, request, response );
                response.setHeader("Content-type", "application/json;charset=UTF-8");
                response.getWriter().write(JSON.toJSONString(result));
            } else if (String.class.equals(method.getReturnType())) {
                String returnUrl = (String) method.invoke(controller, request, response);
                if (!StringUtils.isEmpty(returnUrl)) {
                    if (returnUrl.split(":")[0].equals("redirect")) {
                        response.sendRedirect(returnUrl.split(":")[1]);
                    } else {
                    	String pageName = returnUrl + ".html";
                        RequestDispatcher dispatcher = request.getRequestDispatcher("/" + (pageName.startsWith("/") ? pageName.substring(1) : pageName));
                        dispatcher.forward(request, response);
                    }
                }
            } else {
            	method.invoke(controller, request, response);
            }			
		} catch (Exception e) {
			LOGGER.error("Error raised in DispatcherServlet.", e);
			Map<String, Object> result = new HashMap<String, Object>();
			result.put("status", 500);
			result.put("message", e.getMessage());
			response.setHeader("Content-type", "application/json;charset=UTF-8");
			try {
				response.getWriter().write(JSON.toJSONString(result));
			} catch (IOException ex) {
			}
		}
	}
	
    protected boolean isStaticResource(HttpServletResponse response, String path) throws IOException {
        int index = path.lastIndexOf(".");
        if (index > -1 && index < path.length() - 1) {
            String ext = path.substring(index + 1).toLowerCase();

            String contentType = StringUtils.EMPTY;
            if("css".equals(ext)){
            	contentType = "text/css";
            }else if("html".equals(ext)){
            	contentType = "text/html";
            }else{
            	contentType = MIMETYPE_MAP.getContentType("x." + ext);
            }
            
            response.setHeader("Content-type", contentType + ";charset=UTF-8");
//            String page = this.getServletContext().getRealPath(getResource(path));
//            FileUtils.copy(page, response.getOutputStream());
            return true;
        }
        return false;
    }
    
    protected <A extends Annotation> boolean isAnnotated(Class<?> claze, Class<A> annoClaze) {
        if (claze.getAnnotation(annoClaze) != null) {
            return true;
        }

        Annotation[] annos = claze.getAnnotations();
        for (Annotation anno : annos) {
            if (anno.annotationType().getAnnotation(annoClaze) != null) {
                return true;
            }
        }
        return false;
    } 
    
    public <A extends Annotation> boolean isAnnotated(Field field, Class<A> annoClaze) {
        return field.getAnnotation(annoClaze) != null;
    }

    public <A extends Annotation> boolean isAnnotated(Method method, Class<A> annoClaze) {
        return method.getAnnotation(annoClaze) != null;
    }
}
